import * as Cesium from "cesium";
import DynamicFlowMaterialProperty from "./utils/dynamicFlowMaterial";
import CartesianLatLng from "./utils/cartesianLatLng";
import type { FixedLengthArray } from "@utils";

export interface DrawPolyLineType {
  name: string;
  positions: FixedLengthArray<number, 2>[];
  color: FixedLengthArray<number, 4>;
  width?: number;
  dashLength?: number;
  zIndex?: number;
  data?: any;
}

//绘制实/虚线
class DrawPolyLine {
  #viewer: Cesium.Viewer;
  #positions: FixedLengthArray<number, 2>[];
  #color: FixedLengthArray<number, 4>;
  #width: number;
  #zIndex: number;
  #name: string;
  data: any;
  #dashLength: number;
  entity: (Cesium.Entity & { data?: any; _node?: any }) | null;
  constructor(viewer: Cesium.Viewer, options: DrawPolyLineType) {
    this.#viewer = viewer;
    this.#positions = options.positions;
    this.#color = options.color;
    this.#width = options.width || 1;
    this.data = options.data || {};
    this.#name = options.name;
    this.#dashLength = options.dashLength || 0;
    this.#zIndex = options.zIndex || 1;
    this.entity = null;
    this.#init();
  }
  #init() {
    this.entity = this.#viewer.entities.add({
      name: this.#name,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray([
          ...this.#positions.flat(),
        ]),
        width: this.#width,
        zIndex: this.#zIndex,
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.fromBytes(
            this.#color[0] * 255,
            this.#color[1] * 255,
            this.#color[2] * 255,
            this.#color[3] * 255
          ),
          dashLength: this.#dashLength, //短划线长度
        }),
      },
    });
    this.entity.data = this.data;
    this.entity._node = this;
  }
  click(e: any, _data?: any) {}
  setShow(show: boolean) {
    this.entity!.show = show;
  }
  update() {}
  destroy() {
    if (this.entity) {
      this.#viewer.entities.remove(this.entity);
      this.entity = null;
    }
  }
}
export interface RailwaylineType {
  name: string;
  positions: FixedLengthArray<number, 2>[];
  color: FixedLengthArray<number, 4>;
  gapColor: FixedLengthArray<number, 4>;
  dashLength: number;
  width?: number;
  data?: any;
  zIndex?: number;
}
// 绘制铁路线
class DrawRailwayLine {
  #viewer: Cesium.Viewer;
  #name: string;
  #positions: FixedLengthArray<number, 2>[];
  #color: FixedLengthArray<number, 4>;
  #gapColor: FixedLengthArray<number, 4>;
  #dashLength: number;
  #zIndex: number;
  #width: number;
  data: any;
  entity: (Cesium.Entity & { data?: any; _node?: any }) | null;
  constructor(viewer: Cesium.Viewer, options: RailwaylineType) {
    this.#viewer = viewer;
    this.entity = null;
    this.#name = options.name;
    this.#color = options.color;
    this.#gapColor = options.gapColor;
    this.#positions = options.positions;
    this.#zIndex = options.zIndex || 1;
    this.#width = options.width || 1;
    this.#dashLength = options.dashLength;
    this.data = options.data;
    this.#init();
  }
  #init() {
    this.entity = this.#viewer.entities.add({
      name: this.#name,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray([
          ...this.#positions.flat(),
        ]),
        width: this.#width,
        zIndex: this.#zIndex,
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.fromBytes(
            this.#color[0] * 255,
            this.#color[1] * 255,
            this.#color[2] * 255,
            this.#color[3] * 255
          ),
          gapColor: Cesium.Color.fromBytes(
            this.#gapColor[0] * 255,
            this.#gapColor[1] * 255,
            this.#gapColor[2] * 255,
            this.#gapColor[3] * 255
          ),
          dashLength: this.#dashLength,
        }),
      },
    });
  }
  click(_e: any, _data?: any) {}
  setShow(show: boolean) {
    this.entity!.show = show;
  }
  update() {}
  destroy() {
    if (this.entity) {
      this.#viewer.entities.remove(this.entity);
      this.entity = null;
    }
  }
}
// 编辑线
class EditPolyLine {
  #viewer: Cesium.Viewer;
  entity: (Cesium.Entity & { data?: any; _node?: any }) | null;
  constructor(viewer: Cesium.Viewer, options: any) {
    this.#viewer = viewer;
    this.entity = null;
    this.#init();
  }
  #init() {}
  destroy() {
    if (this.entity) {
      this.#viewer.entities.remove(this.entity);
      this.entity = null;
    }
  }
}
// 水平流线
class HorizontalStreamline {}
export interface VerticalStreamlineType {
  data: Array<{
    lon: number;
    lat: number;
    startHeight: number;
    endHeight: number;
    color: FixedLengthArray<number, 4>;
  }>;
  width?: number;
}
// 垂直流线
class VerticalStreamline {
  #viewer: Cesium.Viewer;
  #data: Array<{
    lon: number;
    lat: number;
    startHeight: number;
    endHeight: number;
    color: FixedLengthArray<number, 4>;
  }>;
  #width: number;
  #entityList: any[];
  constructor(viewer: Cesium.Viewer, options: VerticalStreamlineType) {
    this.#viewer = viewer;
    this.#data = options.data;
    this.#width = options.width || 2;
    this.#entityList = [];
    this.#init();
  }
  #init() {
    for (let i = 0; i < this.#data.length; i++) {
      let entity = this.#viewer.entities.add({
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArrayHeights([
            this.#data[i].lon,
            this.#data[i].lat,
            this.#data[i].startHeight,
            this.#data[i].lon,
            this.#data[i].lat,
            this.#data[i].endHeight,
          ]),
          width: this.#width,
          material: new DynamicFlowMaterialProperty(
            Cesium.Color.fromBytes(
              this.#data[i].color[0] * 255,
              this.#data[i].color[1] * 255,
              this.#data[i].color[2] * 255,
              this.#data[i].color[3] * 255
            ),
            10,
            0,
            0.3
          ),
        },
      });
      this.#entityList.push(entity);
    }
  }
  destroy() {
    for (let i = 0; i < this.#entityList.length; i++) {
      this.#viewer.entities.remove(this.#entityList[i]);
    }
    this.#entityList = [];
  }
}
// 弧度飞线
class RadianFlyingLine {}

/**
 * 采集线
 * 获取鼠标左键拾取 右键删除 中间结束
 */
class AcquisitionLine {
  #viewer: Cesium.Viewer;
  #gatherPoints: any[];
  #points: any[];
  #gatherPolyline: (Cesium.Entity & { data?: any; _node?: any }) | null;
  #dottedLine: (Cesium.Entity & { data?: any; _node?: any }) | null;
  #dots: Array<{ lng: number; lat: number; height: number }>;
  #handler: Cesium.ScreenSpaceEventHandler | null;
  constructor(viewer: Cesium.Viewer) {
    this.#viewer = viewer;
    this.#gatherPoints = [];
    this.#handler = new Cesium.ScreenSpaceEventHandler(
      this.#viewer.scene.canvas
    );
    this.#points = [];
    this.#gatherPolyline = null;
    this.#dottedLine = null;
    this.#dots = [];
  }
  start() {
    this.#gatherPolyline = null;
    this.#handler!.setInputAction((event: any) => {
      //获取加载地形后对应的经纬度和高程：地标坐标
      const ray = this.#viewer.camera.getPickRay(event.position);
      let cartesian = this.#viewer.scene.globe.pick(ray!, this.#viewer.scene);
      //获取倾斜摄影或模型点击处的坐标：场景坐标
      if (!Cesium.defined(cartesian)) {
        return;
      }
      let { lng, lat, height } = CartesianLatLng.CartesianToLatLng(cartesian);
      let point = this.#viewer.entities.add({
        name: "polyline_point",
        position: Cesium.Cartesian3.fromDegrees(lng, lat, height),
        point: {
          color: Cesium.Color.WHITE,
          pixelSize: 5,
          outlineColor: Cesium.Color.BLACK,
          outlineWidth: 1,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      });
      this.#gatherPoints.push(point);
      this.#points.push(cartesian);
      if (this.#points.length >= 2) {
        if (this.#gatherPolyline == null) {
          this.#gatherPolyline = this.#viewer.entities.add({
            polyline: {
              positions: new Cesium.CallbackProperty((time, result) => {
                return this.#points;
              }, false),
              width: 10.0,
              clampToGround: true,
              material: new Cesium.PolylineGlowMaterialProperty({
                color: Cesium.Color.CHARTREUSE.withAlpha(0.5),
              }),
            },
          });
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    this.#handler!.setInputAction((event: any) => {
      if (this.#points.length > 0) {
        this.#viewer.entities.remove(this.#points[this.#points.length - 1]);
        this.#points.pop();
      }

      if (this.#gatherPoints.length > 0) {
        this.#viewer.entities.remove(
          this.#gatherPoints[this.#gatherPoints.length - 1]
        );
        this.#gatherPoints.pop();
      }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    // 鼠标中间结束
    this.#handler!.setInputAction((event: any) => {
      let dke = (this.#gatherPolyline as any).polyline.positions.getValue();
      this.#dots = [];
      for (let i = 0; i < dke.length; i++) {
        let { lng, lat, height } = CartesianLatLng.CartesianToLatLng(dke[i]);
        this.#dots.push({
          lng,
          lat,
          height,
        });
      }
      if (this.#dottedLine) {
        this.#viewer.entities.remove(this.#dottedLine);
        this.#dottedLine = null;
      }
      for (let i = 0; i < this.#gatherPoints.length; i++) {
        this.#viewer.entities.remove(this.#gatherPoints[i]);
      }
      for (let i = 0; i < this.#points.length; i++) {
        this.#viewer.entities.remove(this.#points[i]);
      }
      dke = [];
      this.#gatherPoints = [];
      this.#points = [];
      this.#viewer.entities.remove(this.#gatherPolyline as Cesium.Entity);
      this.#gatherPolyline = null;
      this.#handler!.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE); //移除事件
      this.#handler!.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); //移除事件
      this.#handler!.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK); //移除事件
      this.#handler!.removeInputAction(Cesium.ScreenSpaceEventType.MIDDLE_DOWN); //移除事件
      this.#handler = null;
      console.log("getPoint", this.getPoint());
    }, Cesium.ScreenSpaceEventType.MIDDLE_DOWN);
    // 鼠标移动带动虚线
    this.#handler!.setInputAction((event: any) => {
      let ray = this.#viewer.camera.getPickRay(event.endPosition);
      let cartesian = this.#viewer.scene.globe.pick(ray!, this.#viewer.scene);
      //获取倾斜摄影或模型点击处的坐标：场景坐标
      if (!Cesium.defined(cartesian)) {
        return;
      }
      let { lng, lat, height } = CartesianLatLng.CartesianToLatLng(cartesian);
      if (this.#points.length > 0) {
        if (this.#dottedLine) {
          this.#viewer.entities.remove(this.#dottedLine);
          this.#dottedLine = null;
        }
        this.#dottedLine = this.#viewer.entities.add({
          polyline: {
            positions: new Cesium.CallbackProperty((time, result) => {
              if (this.#points.length > 0) {
                return [
                  this.#points[this.#points.length - 1],
                  Cesium.Cartesian3.fromDegrees(lng, lat, height),
                ];
              } else {
                return [];
              }
            }, false),
            width: 5,
            clampToGround: true,
            material: new Cesium.PolylineDashMaterialProperty({
              color: Cesium.Color.CHARTREUSE.withAlpha(0.5),
            }),
          },
        });
      } else {
        if (this.#dottedLine) {
          this.#viewer.entities.remove(this.#dottedLine);
          this.#dottedLine = null;
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  }
  getPoint() {
    return this.#dots;
  }
}

export {
  DrawPolyLine,
  DrawRailwayLine,
  VerticalStreamline,
  AcquisitionLine,
  EditPolyLine, // TODO: 未完成
  HorizontalStreamline, // TODO: 未完成
  RadianFlyingLine, // TODO: 未完成
};
